const obj = {
    id: 1
}

const id = 2;

function sayId() {
    return () => {
        console.log(this.id);
    }
}

function bind(obj) {
    return sayId.call(obj);
}

const newFn = bind(obj);
newFn();

// 下面为MDN的两种polyfill方法，下面第一种不支持使用new调用新创建的构造函数，而第二种支持。
// 方法一，不支持new
// 你可以将这段代码插入到你的脚本开头，从而使你的 bind() 在没有内置实现支持的环境中也可以部分地使用bind。
// Does not work with `new (funcA.bind(thisArg, args))`
if (!Function.prototype.bind)(function () {
    var slice = Array.prototype.slice;
    Function.prototype.bind = function () {
        var context = this,
            thatArg = arguments[0];
        var args = slice.call(arguments, 1);
        if (typeof context !== 'function') {
            // closest thing possible to the ECMAScript 5
            // internal IsCallable function
            throw new TypeError('Function.prototype.bind - ' +
                'what is trying to be bound is not callable');
        }
        return function () {
            var funcArgs = args.concat(slice.call(arguments))
            return context.apply(thatArg, funcArgs);
        };
    };
})();

// 方法二，支持new
//  Yes, it does work with `new (funcA.bind(thisArg, args))`
if (!Function.prototype.bind)(function () {
    var ArrayPrototypeSlice = Array.prototype.slice;
    Function.prototype.bind = function (otherThis) {
        if (typeof this !== 'function') {
            // closest thing possible to the ECMAScript 5
            // internal IsCallable function
            throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
        }

        var baseArgs = ArrayPrototypeSlice.call(arguments, 1),
            baseArgsLength = baseArgs.length,
            fToBind = this,
            fNOP = function () {},
            fBound = function () {
                baseArgs.length = baseArgsLength; // reset to default base arguments
                baseArgs.push.apply(baseArgs, arguments);
                return fToBind.apply(
                    fNOP.prototype.isPrototypeOf(this) ? this : otherThis, baseArgs
                );
            };

        if (this.prototype) {
            // Function.prototype doesn't have a prototype property
            fNOP.prototype = this.prototype;
        }
        fBound.prototype = new fNOP();

        return fBound;
    };
})();